package ace.module.sms.supplier.api.sms4j.core.impl;

import ace.cmp.core.model.R;
import ace.cmp.i18n.api.MessageSourceAssertService;
import ace.cmp.json.api.JsonService;
import ace.module.sms.supplier.api.SmsHandler;
import ace.module.sms.supplier.api.dto.SupplierConfigDto;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.aliyun.config.AlibabaConfig;
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.api.universal.SupplierConfig;
import org.dromara.sms4j.cloopen.config.CloopenConfig;
import org.dromara.sms4j.comm.constant.SupplierConstant;
import org.dromara.sms4j.comm.exception.SmsBlendException;
import org.dromara.sms4j.ctyun.config.CtyunConfig;
import org.dromara.sms4j.dingzhong.config.DingZhongConfig;
import org.dromara.sms4j.emay.config.EmayConfig;
import org.dromara.sms4j.huawei.config.HuaweiConfig;
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
import org.dromara.sms4j.lianlu.config.LianLuConfig;
import org.dromara.sms4j.netease.config.NeteaseConfig;
import org.dromara.sms4j.provider.factory.BaseProviderFactory;
import org.dromara.sms4j.provider.factory.ProviderFactoryHolder;
import org.dromara.sms4j.tencent.config.TencentConfig;
import org.dromara.sms4j.unisms.config.UniConfig;
import org.dromara.sms4j.yunpian.config.YunpianConfig;
import org.dromara.sms4j.zhutong.config.ZhutongConfig;

/**
 * @author caspar
 * @date 2023/10/24 18:43
 */
@Slf4j
public class Sms4JSmsHandler implements SmsHandler {
  private static final Map<String, Function<String, SupplierConfig>> configResolverMap =
      new HashMap<>();
  private final JsonService jsonService;
  private final MessageSourceAssertService assertService;
  private final SupplierConfigDto configDto;
  private final SupplierConfig supplierConfig;
  private final SmsBlend smsBlend;

  public Sms4JSmsHandler(
      SupplierConfigDto configDto,
      JsonService jsonService,
      MessageSourceAssertService assertService) {
    this.jsonService = jsonService;
    this.initConfigResolverMap(jsonService);
    this.assertService = assertService;
    this.configDto = configDto;
    this.supplierConfig = this.constructSupplierConfig(configDto);
    this.smsBlend = this.initSmsBlend(this.supplierConfig);
  }

  @Override
  public R<Void> send(String phoneNumber, String content) {
    SmsResponse response = smsBlend.sendMessage(phoneNumber, content);
    if (response.isSuccess()) {
      return R.ok();
    } else {
      log.error("send_message_fail,{}", response);
      return R.fail();
    }
  }

  @Override
  public R<Void> send(String phoneNumber, Map<String, String> contentParams) {
    SmsResponse response = smsBlend.sendMessage(phoneNumber, new LinkedHashMap<>(contentParams));
    if (response.isSuccess()) {
      return R.ok();
    } else {
      log.error("send_message_fail,{}", response);
      return R.fail();
    }
  }

  private SmsBlend initSmsBlend(SupplierConfig config) {
    BaseProviderFactory factory = ProviderFactoryHolder.requireForSupplier(config.getSupplier());
    if (factory == null) {
      throw new SmsBlendException("不支持当前供应商配置");
    }
    SmsBlend sms = factory.createSms(config);
    return sms;
  }

  private SupplierConfig constructSupplierConfig(SupplierConfigDto configDto) {

    Map<String, String> configMap =
        this.jsonService.toMap(configDto.getConfig(), String.class, String.class);

    String supplierValue = configMap.get("supplier");

    assertService.isEmpty(
        supplierValue,
        this.getClass().getName() + ".error-supplier-value-cannot-be-empty",
        "supplier配置不能为空");

    Function<String, SupplierConfig> resolverFn = configResolverMap.get(supplierValue);

    assertService.isNull(
        resolverFn,
        this.getClass().getName() + ".error-not-suport-supplier",
        new Object[] {supplierValue},
        "supplier值[{0}]配置不支持");

    return resolverFn.apply(configDto.getConfig());
  }

  private void initConfigResolverMap(JsonService jsonService) {
    if (!configResolverMap.isEmpty()) {
      return;
    }
    configResolverMap.put(
        SupplierConstant.ALIBABA, config -> jsonService.toObject(config, AlibabaConfig.class));
    configResolverMap.put(
        SupplierConstant.CLOOPEN, config -> jsonService.toObject(config, CloopenConfig.class));
    configResolverMap.put(
        SupplierConstant.CTYUN, config -> jsonService.toObject(config, CtyunConfig.class));
    configResolverMap.put(
        SupplierConstant.EMAY, config -> jsonService.toObject(config, EmayConfig.class));
    configResolverMap.put(
        SupplierConstant.HUAWEI, config -> jsonService.toObject(config, HuaweiConfig.class));
    configResolverMap.put(
        SupplierConstant.DINGZHONG, config -> jsonService.toObject(config, DingZhongConfig.class));
    configResolverMap.put(
        SupplierConstant.JDCLOUD, config -> jsonService.toObject(config, JdCloudConfig.class));
    configResolverMap.put(
        SupplierConstant.LIANLU, config -> jsonService.toObject(config, LianLuConfig.class));
    configResolverMap.put(
        SupplierConstant.NETEASE, config -> jsonService.toObject(config, NeteaseConfig.class));
    configResolverMap.put(
        SupplierConstant.TENCENT, config -> jsonService.toObject(config, TencentConfig.class));
    configResolverMap.put(
        SupplierConstant.UNISMS, config -> jsonService.toObject(config, UniConfig.class));
    configResolverMap.put(
        SupplierConstant.YUNPIAN, config -> jsonService.toObject(config, YunpianConfig.class));
    configResolverMap.put(
        SupplierConstant.ZHUTONG, config -> jsonService.toObject(config, ZhutongConfig.class));
  }
}
